﻿# coding: utf-8

import time
import wx

import mk3de
import Engine
import Camera
import RenderDevice
import ToolTranslation
import ToolRotation
import ToolScale
import SceneNode
import SceneManager
import Painter
import Profiler
import EntityModel
import Model
import Skeleton
import SkeletonData
import RenderWindow
import RenderFrame
import RenderStepViewCulling
import RenderStepSceneRender
import CullingProcessorDefault
import RefCounter

import SceneEditor

class OperateDefine:
	OP_SELECT = wx.NewId()
	OP_TRANSLATION = wx.NewId()
	OP_ROTATION = wx.NewId()
	OP_SCALING = wx.NewId()
	OP_BUILD_SINGLE = wx.NewId()
	OP_TERRAIN_HEIGHT_PAINT = wx.NewId()
	OP_TERRAIN_LAYER_PAINT = wx.NewId()
	OP_LOGIC_GRID_PAINT = wx.NewId()	

	@staticmethod
	def IsOperate(op):
		if op == OperateDefine.OP_SELECT or\
		 op == OperateDefine.OP_TRANSLATION or\
		 op == OperateDefine.OP_ROTATION or\
		 op == OperateDefine.OP_SCALING or\
		 op == OperateDefine.OP_BUILD_SINGLE or\
		 op == OperateDefine.OP_TERRAIN_HEIGHT_PAINT or\
		 op == OperateDefine.OP_TERRAIN_LAYER_PAINT or\
		 op == OperateDefine.OP_LOGIC_GRID_PAINT:
			return True
		return False

__builtins__['OPD'] = OperateDefine()

class CWorldEditor:
	"""
	Main world editor module.
	"""

	def __init__(self):
		""" Default class constructor """

		self._mouseMiddleDownPos = None
		self._mouseRightDownPos = None
		self._inputHandler = SCENE_EDITOR
		self._currentOp = OPD.OP_SELECT
		self._lastTime = time.clock()
		self._isMouseCaptured = False

	def CreateEngine(self):
		""" Initialise the mk3d engine """
		
		hWnd = PANEL_EDITOR_SCENE.GetHandle()
		if not mk3de.CreateEngine(Engine.RDT_DIRECT3D9, hWnd):
			return False
				
		return True
						
	def CreateEditor(self):
		""" Create world editor """
		
		# Create transform tools
		TRANSLATION_TOOL.Create()
		ROTATION_TOOL.Create()
		SCALE_TOOL.Create()

		# Create scene editor.
		SCENE_EDITOR.Create()

		# Create terrain editor.
		TERRAIN_EDITOR.Create()
		
		# Create main render window.
		self.__CreateMainRenderWindow(PANEL_EDITOR_SCENE.GetHandle())

		return True

	def __CreateMainRenderWindow(self, hWnd):
		renderWindow = Engine.CreateRenderWindow(hWnd)
		RenderFrame.MakeDefaultRenderSteps(renderWindow)
		
		renderStepViewCulling = RenderFrame.GetRenderStepByName(renderWindow, RenderStepViewCulling.RenderStepName)
		RenderStepViewCulling.SetCamera(renderStepViewCulling, SCENE_EDITOR._mainCameraHandle)
		cullingProcessorDefault = CullingProcessorDefault._New()
		RenderStepViewCulling.SetCullingProcessor(renderStepViewCulling, cullingProcessorDefault)
		RefCounter.Release(cullingProcessorDefault)
		RenderStepViewCulling.SetScene(renderStepViewCulling, SCENE_EDITOR._root.GetCoreHandle())
		
		renderStepSceneRender = RenderFrame.GetRenderStepByName(renderWindow, RenderStepSceneRender.RenderStepName)        
		RenderStepSceneRender.SetClearParam(renderStepSceneRender, True, True, True, 0xff808080, 1.0, 0)
		
	def Destroy(self):
		TRANSLATION_TOOL.Destroy()
		ROTATION_TOOL.Destroy()
		SCALE_TOOL.Destroy()
		SCENE_EDITOR.Destroy()
		TERRAIN_EDITOR.Destroy()
		LOGIC_GRID_EDITOR.Destroy()
		mk3de.DestroyEngine()

	def GetCurrentOperate(self):
		""" Get the current operate """

		return self._currentOp

	def ChangeCurrentOperate(self, op, notify = True):
		"""
		Change the current operate.
		
		Parameters:
		@param op - the operate define, must from OP
		"""
		
		# Check whether the param op is OperateDefine
		if not OPD.IsOperate(op):
			return
				
		# If the new operate is the same as current operate, then return
		if self._currentOp == op:
			return
		
		# Change current operate
		self._currentOp = op
		
		# Change input handler
		if op == OPD.OP_SELECT:
			self.__ChangeInputHandler(SCENE_EDITOR)
		elif op == OPD.OP_TRANSLATION:
			self.__ChangeInputHandler(TRANSLATION_TOOL)
		elif op == OPD.OP_ROTATION:
			self.__ChangeInputHandler(ROTATION_TOOL)
		elif op == OPD.OP_SCALING:
			self.__ChangeInputHandler(SCALE_TOOL)
		elif op == OPD.OP_BUILD_SINGLE:
			self.__ChangeInputHandler(BUILDER_SINGLE)
		elif op == OPD.OP_TERRAIN_HEIGHT_PAINT or op == OPD.OP_TERRAIN_LAYER_PAINT:
			self.__ChangeInputHandler(TERRAIN_EDITOR)
		elif op == OPD.OP_LOGIC_GRID_PAINT:
			self.__ChangeInputHandler(LOGIC_GRID_EDITOR)
		
		# Notify UI refresh
		if notify:
			wx.GetApp().GetMainFrame().OnCurrentOperateChanged()

	def __ChangeInputHandler(self, newHandler, **p):
		"""
		Change the input handler

		Parameters:
		@param newHandle - the new input handler, if it's None, then use the 'SCENE_EDITOR'
		@param **p - extra parameters
		"""

		if self._inputHandler:
			self._inputHandler.OnExit()

		if not newHandler:
			newHandler = SCENE_EDITOR

		newHandler.OnEnter(**p)

		self._inputHandler = newHandler

	def Update(self):
		now = time.clock()
		dt = int((now - self._lastTime) * 1000)
		
		Engine.Update()
		SCENE_EDITOR.Update(dt)
		TERRAIN_EDITOR.Update(dt)
		TRANSLATION_TOOL.Update()
		ROTATION_TOOL.Update()
		SCALE_TOOL.Update()
		
		self._lastTime = self._lastTime + dt * 0.001
		time.sleep(0.001)

	def Render(self):
		self.__RenderMainWindow()
			
	def __RenderMainWindow(self):
		hWnd = PANEL_EDITOR_SCENE.GetHandle()
		renderWindow = Engine.GetRenderWindow(hWnd)
		Engine.SetCurrentRenderWindow(renderWindow)
		
		width = RenderWindow.GetWidth(renderWindow)
		height = RenderWindow.GetHeight(renderWindow)
		RenderDevice.SetViewport(0, 0, width, height, 0, 1.0)
		
		RenderDevice.BeginFrame()
		Profiler.BeginFrame()
		
		RenderFrame.Render(renderWindow)
		self.__RenderGrid()
		TERRAIN_EDITOR.Render()
		SCENE_EDITOR.Render()
		self.__RenderTransformTools()
		LOGIC_GRID_EDITOR.Render()
		
		Profiler.ShowStatistics()
		Profiler.EndFrame()
		
		Painter.Flush()
		
		RenderDevice.EndFrame()
		RenderDevice.Present(renderWindow)

	def __RenderTransformTools(self):
		RenderDevice.Clear(0, 1, 1, 0xff000000, 1.0, 0)
		TRANSLATION_TOOL.Render()
		ROTATION_TOOL.Render()
		SCALE_TOOL.Render()
						
	def __RenderGrid(self):
		for i in xrange(0, 501, 50):
			Painter.DrawLine3D(0, 0, i, 500, 0, i, 0xffa0a0a0, 0xffa0a0a0)
		for i in xrange(0, 501, 50):
			Painter.DrawLine3D(i, 0, 0, i, 0, 500, 0xffa0a0a0, 0xffa0a0a0)

		Painter.DrawLine3D(0, 0, 0, 500, 0, 0, 0xff404040, 0xff404040);
		Painter.DrawLine3D(0, 0, 0, 0, 0, 500, 0xff404040, 0xff404040);
		Painter.Flush()

	def OnRenderWindowResize(self, hWnd):
		Engine.OnRenderWindowResize(hWnd)

	def OnMouseMiddleDown(self, e):
		PANEL_EDITOR_SCENE.CaptureMouse()
		self._isMouseCaptured = True
		self._mouseMiddleDownPos = e.GetPosition()

	def OnMouseMiddleUp(self, e):
		if self._isMouseCaptured:
			PANEL_EDITOR_SCENE.ReleaseMouse()
			self._isMouseCaptured = False
		self._mouseMiddleDownPos = None
		
	def OnMouseLeftDown(self, e):
		PANEL_EDITOR_SCENE.CaptureMouse()
		self._isMouseCaptured = True
		if self._inputHandler:
			self._inputHandler.OnMouseLeftDown(e)   
				
	def OnMouseLeftUp(self, e):
		if self._isMouseCaptured:
			PANEL_EDITOR_SCENE.ReleaseMouse()
			self._isMouseCaptured = False
		if self._inputHandler:
			self._inputHandler.OnMouseLeftUp(e)
				
	def OnMouseRightDown(self, e):
		PANEL_EDITOR_SCENE.CaptureMouse()
		self._isMouseCaptured = True
		self._mouseRightDownPos = e.GetPosition()
		
		if self._inputHandler:
			self._inputHandler.OnMouseRightDown(e)
				 
	def OnMouseRightUp(self, e):
		if self._isMouseCaptured:
			PANEL_EDITOR_SCENE.ReleaseMouse()
			self._isMouseCaptured = False
		self._mouseRightDownPos = None
		
		if self._inputHandler:
			self._inputHandler.OnMouseRightUp(e)
		
	def OnMouseMotion(self, e):
		if self._inputHandler:
			self._inputHandler.OnMouseMotion(e)

		if (not self._mouseMiddleDownPos and not self._mouseRightDownPos) or not e.Dragging():
			return

		pos = e.GetPosition()
		cam = Engine.GetCurrentCamera()
		if self._mouseRightDownPos:
			Camera.RotationAxisY(cam, -(pos[0] - self._mouseRightDownPos[0]) / 100.0)
			Camera.RotationViewX(cam, -(pos[1] - self._mouseRightDownPos[1]) / 100.0)
			Camera.Update(cam, 0)
			self._mouseRightDownPos = pos
		elif self._mouseMiddleDownPos:
			Camera.MoveViewX(cam, pos[0] - self._mouseMiddleDownPos[0])
			Camera.MoveAxisY(cam, pos[1] - self._mouseMiddleDownPos[1])
			Camera.Update(cam, 0)
			self._mouseMiddleDownPos = pos

	def OnMouseWheel(self, e):
		cam = Engine.GetCurrentCamera()
		if e.ControlDown():
			Camera.MoveViewZ(cam, e.m_wheelRotation * 5)
		else:
			Camera.MoveViewZ(cam, e.m_wheelRotation / 2)

	def OnKeyDown(self, e):        
		if self._inputHandler:
			self._inputHandler.OnKeyDown(e)
				 
	def OnKeyUp(self, e):
		if self._inputHandler:
			self._inputHandler.OnKeyUp(e)            

	def OnMouseCaptureLost(self, e):
		self._isMouseCaptured = False
			
__builtins__['WORLD_EDITOR'] = CWorldEditor()
